/**
 * render() {
 *     _c解析标签
 *     _v文本内容
 *     _s 插值表达式
 *    这个文件期望把ast语法树，转成render函数字符串
 *    return _c('div',{id: app,style:{},_v('文本')}
 *
 *  }
 */

/**
 * 匹配 双花括号语法 {{}} 匹配到的是就是双花括号的 变量
 */
export const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g;

/**
 *  <div id="app">hello: {{name}} <h1>我是子h1标签<span>我是span</span></h1></div>
 *   render() {  _c解析标签
 *     return _c("div",{id: 'app'},_v('hello'+_s(msg)),_c("h1"))
 *    }
 *
 *   原理：ast==>拼接字符串 => render函数
 */

//处理属性----样式篇
function genPorps(attrs) {
  let str = "";
  //通过上面转的ast语法树 ，attrs是数组对象，可以通过打印来查看
  // {name: 'style', value: 'color: red;font-size: 12px;'} ==>  style: {color: red,font-size: '20px'}
  for (let i = 0; i < attrs.length; i++) {
    let currentItem = attrs[i];
    if (currentItem.name == "style") {
      // 内联 style值 行内样式
      let obj = {};
      currentItem.value.split(";").forEach((item) => {
        if (item) {
          //去掉结尾的;空值
          let valArr = item.split(":");
          obj[valArr[0]] = valArr[1];
        }
      });
      currentItem.value = obj;
    }
    str = str + `${currentItem.name}:${JSON.stringify(currentItem.value)},`;
  }
  return `{${str.slice(0, -1)}}`; //返回去掉最后一个,
}
//处理子节点（1）
function getChildren(ast) {
  let hasChildren = ast.children; //[]  ast语法树中 所有的子节点 都是放到children这个数组中的，遍历处理每个子节点
  if (hasChildren) {
    return hasChildren.map((child) => genchild(child)).join(","); // [{},{}] ===> '{},{}' 变成字符串
  }
}

//具体的处理节点（2）根据节点生成子字符串形式
function genchild(child) {
  //儿子的类型 nodeType 元素节点div等（1） 属性节点（2） 文本节点（3）
  if (child.type == 1) {
    //如果是元素---继续递归---重新走===>_cCode 和attrsCode的生成
    return generate(child);
  } else {
    // 文本 （1）只是普通文本  （2）含有插值表达{{}}
    let text = child.text; //获取文本

    if (!defaultTagRE.test(text)) {
      //(1) 普通文本
      return `_v(${JSON.stringify(text)})`;
    } else {
      //(2) 处理插值表达式 {{}}  ====>实际程序员所写代码 hello {{}} ,{{}},你好{{}}
      let tokens = []; //保存每段代码
      let lastIndex = (defaultTagRE.lastIndex = 0); // 正则/g全局匹配的时候，多次调用需要把lastIndex = 0初始化，不然他会从上次匹配位置开始
      let match;
      while ((match = defaultTagRE.exec(text))) {
        //exec正则方法
        // console.log(match, 'match')
        //hello {{msg}}
        let index = match.index;
        console.log(index, lastIndex, match, "index--lastIndex");
        //添加内容
        if (index >= lastIndex) {
          tokens.push(JSON.stringify(text.slice(lastIndex, index))); //切割内容 存内容 hello:

          // {{}} trim方法是字符串去空
          tokens.push(`_s(${match[1].trim()})`);
          lastIndex = index + match[0].length; //解析到第一个{{}}插值表达式，更新lastindex位置
        }
      }
      // 最后一次匹配后还有内容
      if (lastIndex < text.length) {
        tokens.push(JSON.stringify(text.slice(lastIndex))); // 存内容 我是:
      }
      //最终返回出去
      return `_v(${tokens.join("+")})`;
    }
  }
}

export function generate(ast) {
  // 递归
  let children = getChildren(ast); //递归处理嵌套的子节点信息
  console.log(children, "children-generate-func");
  //注意属性 有个style内联属性问题 rendern函数中对样式属性写法一般是 {id: app,style: {color: red,font-size: '20px'}}

  let code = `_c('${ast.tag}',
    ${ast.attrs.length ? genPorps(ast.attrs) : "undefined"}
    ${children ? `,${children}` : ""})`;
  console.log(code, "codecode---输出结果");
  return code;
}
